package com.oner365.test.futureDemo;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Runnable VS Callable
 * 对比                   Runnable      Callable
 * 方法返回值               不可以          可以
 * 异常                    不可以          可以
 * 在thread中执行           可以           不可以
 * 在ExecutorService中使用  可以           可以
 */
public class CallableFutureDemo {
  
  private static final Logger LOGGER = LoggerFactory.getLogger(CallableFutureDemo.class);
  
  public static void callableExample() throws InterruptedException, ExecutionException {
    ExecutorService executorService = Executors.newSingleThreadExecutor();
    Callable<String> callable = () ->{
      TimeUnit.SECONDS.sleep(2);
      LOGGER.info("callable.call()");
      //callable会抛出异常，不需要try/catch
      return "this is result";
    };
    Future<String> future = executorService.submit(callable);
    //返回类型为FutureTask，此类实现了RunnableFuture类
    //RunnableFuture类继承了Future和Runnable
    //使得FutureTask具有Future和Runnable特性
    //可在ExecutorService中配合线程使用
    //可以通过Future获取执行结果
    //执行顺序
    //1、通过实现Callable接口定义一个带返回值的任务
    //2、通过线程池submit方法提交Callable对象
    //3、submit方法构造FutureTask交给线程池执行，同时返回FutureTask用于结果的获取
    //4、线程池将FutureTask交给线程执行
    //5、线程执行FutureTask的run方法
    //6、FutureTask的run方法执行Callable对象的call方法，并将结果保存在outcome中
    //7、通过返回的FutureTask获取outcome中执行结果
   
    LOGGER.info("返回类:"+future.getClass());
    long startTime = System.currentTimeMillis();
    //通过isDone方法获取线程是否执行完毕
    while(!future.isDone()) {
      LOGGER.info("子线程执行中......");
      TimeUnit.SECONDS.sleep(1);
      if((System.currentTimeMillis() - startTime)/1000 >= 3) {
        //如果发起cancel时任务还没有开始运行，则随后任务就不会被执行；
        //如果发起cancel时任务已经在运行了，则这时就需要看 mayInterruptIfRunning 参数了：
        //如果mayInterruptIfRunning 为true, 则当前在执行的任务会被中断
        //如果mayInterruptIfRunning 为false, 则可以允许正在执行的任务继续运行，直到它执行完
        future.cancel(true);
      }
    }
    //由于future的get方法已定义了在cancelled时get会返回CancellationException，所以取消执行用isCancelled方法处理异常
    if(!future.isCancelled()) {
    //future获取执行结果，在获取执行结果时主线程会停止执行等待子线程执行完毕
      String result = future.get();
      LOGGER.info(result);
    }else {
      LOGGER.info("子线程取消");
    }
    
    
    executorService.shutdown();
  }

  public static void main(String[] args) throws InterruptedException, ExecutionException {
    callableExample();
  }
}
